/****************************************************************************
 * Copyright 2009 Huascar A. Sanchez                                        *
 *                                                                          *
 * Licensed under the Apache License, Version 2.0 (the "License");          *
 * you may not use this file except in compliance with the License.         *
 * You may obtain a copy of the License at                                  *
 *                                                                          *
 *     http://www.apache.org/licenses/LICENSE-2.0                           *
 *                                                                          *
 * Unless required by applicable law or agreed to in writing, software      *
 * distributed under the License is distributed on an "AS IS" BASIS,        *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
 * See the License for the specific language governing permissions and      *
 * limitations under the License.                                           *
 ****************************************************************************/
package com.gotobject.filter.common;

import com.gotobject.filter.FilterImpl;
import static com.gotobject.filter.common.Predicates.contains;
import static com.gotobject.filter.common.Predicates.not;
import com.gotobject.filter.spi.IterableFileReader;
import com.gotobject.filter.spi.IterableStringReader;

import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author huascar.sanchez@gmail.com (Huascar A. Sanchez)
 */
public class Iterables {
    private Iterables(){}

	private static <T> void addAll(Collection<T> src, Iterable<? extends T>... iterables){
		for(Iterable<? extends T> each : iterables){
			src.addAll(asCollection(capturedWildCard(each)));
		}
	}

    @SuppressWarnings({"unchecked"})
    public static <T> T[] asArray(Iterable<? extends T> iterable){
        final List<T> t = asList(capturedWildCard(iterable));
        if(t.isEmpty()) throw new IllegalArgumentException("empty: no elements to iterate.");
        return t.toArray((T[]) Array.newInstance(t.get(0).getClass(), t.size()));
    }

    public static <T> Collection<T> asCollection(Iterable<T> result){
        final Collection<T>  asCollection = new ArrayList<T>();
        for (T eachT : result) {
            asCollection.add(eachT);
        }

        return asCollection;
    }

    public static Iterable <String> asIterable(File file){
        return new IterableFileReader(file);
    }

    public static Iterable<String> asIterable(String text){
        return new IterableStringReader(text);
    }

    public static <T> List<T> asList(Iterable<T> result){
        final List<T>  asList = new ArrayList<T>();
        for (T eachT : result) {
            asList.add(eachT);
        }

        return asList;
    }

    @SuppressWarnings({"unchecked"})
    public static <T> Iterable<T> cast(Iterable<Object> t){
        return (Iterable<T>) t;
    }


    public static <T> Iterable <T> concat(Iterable<? extends T> a, Iterable<? extends T> b){
		final CopyOnWriteArrayList<T> result = new CopyOnWriteArrayList<T>();
		addAll(result, a, b);
		return result;
	}

    public static <T> Iterable<T> capturedWildCard(Iterable<? extends T> src){
        return new ArrayList<T>(asCollection(src));
    }


	public static <T> Iterable<T> distinct(Iterable<? extends T> t){
		final Set<T> disctinct = new HashSet<T>();
		addAll(disctinct, t);
		return disctinct;
	}

	public static <T> Iterable<T> except(Iterable<? extends T> src, Iterable<? extends T> exceptions){
		return new FilterImpl().from(capturedWildCard(src)).where(not(contains(exceptions))).select();
	}


	public static <T> Iterable<T> intersect(Iterable<? extends T> a, Iterable<? extends T> b) {
		return new FilterImpl().from(capturedWildCard(a)).where(contains(b)).select();
	}


	public static <T> Iterable<T> union(Iterable<? extends T> a, Iterable<? extends T> b) {
		final Set<T> result = new HashSet<T>();
		addAll(result, a, b);
		return result;
	}
}
